package com.app.util.http;

import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.net.ssl.HttpsURLConnection;

/**
 * url客户端
 * **/
public class HttpClient 
{
	public static final String UTF8 = "UTF-8";
	
	public static final String GBK = "GBK";
	
	public static final String POST = "POST";
	
	public static final String GET = "GET";
	
	/**
	 * 超时时间默认5秒
	 * **/
	private int timeout = 5000;
	
	/**
	 * 默认超时5秒
	 * **/
	public HttpClient(){}
	
	/**
	 * 默认超时时间
	 * **/
	public HttpClient setTimeout(int timeout)
	{
		this.timeout = timeout;
		return this;
	}
	
	/**
	 * 参数转换字节
	 * @param Map<String,String> params 参数
	 * **/
	public byte[] paramsToBytes(Map<String,String> params)throws Exception
	{
		StringBuffer data = new StringBuffer();
		for(String key : params.keySet())
		{
			if(data.length() == 0)
				data.append(key).append("=").append(params.get(key));
			else
				data.append("&").append(key).append("=").append(params.get(key));
		}
		
		return data.toString().getBytes();
	}
	
	/**
	 * get请求
	 * @param urlStr  http地址
	 * @param headers 请求头
	 * **/
	public HttpResult get(String urlStr,Map<String,String> headers)
	{
		return getToProxy(urlStr, headers, null, 0);
	}
	
	/**
	 * get请求
	 * @param urlStr  http地址
	 * @param headers 请求头
	 * @param String ip 代理IP
	 * @param int port 代理端口
	 * **/
	public HttpResult getToProxy(String urlStr,Map<String,String> headers,String ip,int port)
	{
		if(urlStr.getBytes().length < 8)
		{
			return null;
		}
		
		if("https://".equals(urlStr.substring(0, 8)))
		{
			if(null == ip)
				return httpsRequest(urlStr,HttpClient.GET,headers,null,null);
			else
				return httpsRequest(urlStr,HttpClient.GET,headers,null,new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ip, port)));
		}
		else if("http://".equals(urlStr.substring(0, 7)))
		{
			if(null == ip)
				return httpRequest(urlStr,HttpClient.GET,headers,null,null);
			else
				return httpRequest(urlStr,HttpClient.GET,headers,null,new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ip, port)));
		}
		else
		{
			return null;
		}
	}
	
	/**
	 * post请求
	 * @param urlStr  http地址
	 * @param headers 请求头
	 * @param params 请求参数
	 * **/
	public HttpResult post(String urlStr,Map<String,String> headers,byte[] bytes)
	{
		return postToProxy(urlStr, headers, bytes, null, 0);
	}
	
	/**
	 * post请求
	 * @param urlStr  http地址
	 * @param headers 请求头
	 * @param params 请求参数
	 * @param String ip 代理IP
	 * @param int port 代理端口
	 * **/
	public HttpResult postToProxy(String urlStr,Map<String,String> headers,byte[] bytes,String ip,int port)
	{
		if(urlStr.getBytes().length < 8)
		{
			return null;
		}
		
		if("https://".equals(urlStr.substring(0, 8)))
		{
			if(null == ip)
				return httpsRequest(urlStr,HttpClient.POST,headers,bytes,null);
			else
				return httpsRequest(urlStr,HttpClient.POST,headers,bytes,new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ip, port)));
		}
		else if("http://".equals(urlStr.substring(0, 7)))
		{
			if(null == ip)
				return httpRequest(urlStr,HttpClient.POST,headers,bytes,null);
			else
				return httpRequest(urlStr,HttpClient.POST,headers,bytes,new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ip, port)));
		}
		else
		{
			return null;
		}
	}
	
	public HttpResult httpRequest(String urlStr,String method,Map<String,String> headers,byte[] bytes,Proxy proxy)
	{
		URL url;
		HttpURLConnection http;
		HttpResult result = new HttpResult();
		try
		{
			url  = new URL(urlStr);
			
			if(null == proxy)
				http = (HttpURLConnection)url.openConnection();
			else
				http = (HttpURLConnection)url.openConnection(proxy);

			return this.request(http, method, headers, bytes, result);
		}
		catch(Exception exe)
		{
			return result.setBody(exe.getMessage().getBytes());
		}
		
	}
	
	public HttpResult httpsRequest(String urlStr,String method,Map<String,String> headers,byte[] bytes,Proxy proxy)
	{
		URL url;
		HttpsURLConnection https;
		HttpResult result = new HttpResult();
		try
		{
			url  = new URL(urlStr);
			if(null == proxy)
				https = (HttpsURLConnection)url.openConnection();
			else
				https = (HttpsURLConnection)url.openConnection(proxy);
	
			return this.request(https, method, headers, bytes, result);
		}
		catch(Exception exe)
		{
			return result.setBody(exe.getMessage().getBytes());
		}
	}
	
	/**
	 * http请求处理
	 * @param HttpURLConnection http 请求客户端
	 * @param String method 方法
	 * @param Map<String,String> headers 请求头
	 * @param Map<String,String> params 请求参数
	 * @param HttpResult result 结果集
	 * **/
	private HttpResult request(HttpURLConnection http,String method,Map<String,String> headers,byte[] bytes,HttpResult result) throws Exception
	{
		http.setDoInput(true);
		http.setDoOutput(true);
		http.setRequestMethod(method);
		http.setUseCaches(false);
		http.setInstanceFollowRedirects(false);
		http.setConnectTimeout(timeout);
		
		//设置请求头
		if(null!= headers)
		{
			for(String key : headers.keySet())
			{
				http.setRequestProperty(key, headers.get(key));
			}
		}

		http.connect();
		
		//发送数据
		if(null != bytes)
			this.sendBytes(http.getOutputStream(), bytes);
		
		//获取响应数据
		this.readResponseBody(http.getInputStream(), http.getErrorStream(), result);
		
		//获取响应头
		this.readResponseHeaders(result, http.getHeaderFields());
		
		//设置响应状态码
		result.setCode(http.getResponseCode());
		
		//关闭客户端连接
		http.disconnect();
		
		return result;

	}
	
	/**
	 * 发送数据(关闭输出流)
	 * @param OutputStream outputStream 输出流
	 * @param byte[] bytes 字节
	 * **/
	private void sendBytes(OutputStream outputStream,byte[] bytes)throws Exception
	{	
		DataOutputStream out = new DataOutputStream(outputStream);
		out.write(bytes);
		out.flush();
		out.close();
		outputStream.close();
	}
	
	/**
	 * 接收返回数据头
	 * @param HttpResult result 结果集
	 * @param Map<String, List<String>> headers 原始响应头
	 * **/
	private void readResponseHeaders(HttpResult result,Map<String, List<String>> headers)throws Exception
	{
		result.setResponseHeads(new HashMap<String,String>());

		for(String key : headers.keySet())
		{
			if(null != key)
			{
				for(String value : headers.get(key))
				{
					result.getResponseHeaders().put(key, value);
				}
			}
		}
	}
	
	/**
	 * 接收返回数据体
	 * @param InputStream bodyInStream 响应体输入流
	 * @param InputStream errorInStream 错误信息输入流
	 * @param HttpResult result 结果集
	 * @param String charset 字符编码
	 * **/
	private void readResponseBody(InputStream bodyInStream,InputStream errorInStream,HttpResult result)throws Exception
	{
		if(null != bodyInStream)
		{
			result.setBody(IoTools.InputStreatToBytes(bodyInStream));
			bodyInStream.close();
		}
		else
		{
			result.setBody(IoTools.InputStreatToBytes(errorInStream));
			errorInStream.close();
		}
	}
	
}